package com.atguigu.spzx.pay.service.impl;

import com.alibaba.fastjson.JSON;
import com.alipay.api.AlipayApiException;
import com.alipay.api.AlipayClient;
import com.alipay.api.DefaultAlipayClient;
import com.alipay.api.domain.AlipayTradeWapPayModel;
import com.alipay.api.internal.util.AlipaySignature;
import com.alipay.api.request.AlipayTradeWapPayRequest;
import com.atguigu.spzx.common.handler.exception.SpzxException;
import com.atguigu.spzx.model.entity.h5.PaymentInfo;
import com.atguigu.spzx.model.entity.order.OrderInfo;
import com.atguigu.spzx.model.result.Result;
import com.atguigu.spzx.model.result.ResultCodeEnum;
import com.atguigu.spzx.order.client.OrderClient;
import com.atguigu.spzx.pay.config.AlipayConfig;
import com.atguigu.spzx.pay.service.AlipayService;
import com.atguigu.spzx.pay.service.PaymentInfoService;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import jakarta.annotation.Resource;
import org.apache.poi.util.StringUtil;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import java.math.BigDecimal;
import java.util.Date;
import java.util.Map;

@Service
public class AlipayServiceImpl implements AlipayService {
    @Resource
    OrderClient orderClient;
    @Resource
    PaymentInfoService paymentInfoService;
    @Override
    public String submitAlipay(Long orderNo) {
        //1、准备构建表单需要的参数列表
        //使用orderId查询订单的详情：远程访问订单服务
        Result<OrderInfo> result = orderClient.getOrderByNo(orderNo);
        if(result.getCode()!=200){
            throw new SpzxException(ResultCodeEnum.FAIL,null);
        }
        OrderInfo orderInfo = result.getData();

        // 商户订单号，商户网站订单系统中唯一订单号，必填
        String out_trade_no = orderInfo.getOrderNo();
        // 订单名称，必填
        String subject = "尚品甄选商品";
        // 付款金额，必填
        String total_amount= orderInfo.getTotalAmount().toString();
        // 销售产品码 必填  表示使用的是h5支付
        String product_code="QUICK_WAP_WAY";
        //2、 SDK 公共请求类，包含公共请求参数，以及封装了签名与验签，开发者无需关注签名与验签
        //调用RSA签名方式  创建alipay请求客户端 并配置参数(加密方式 秘钥 支付请求地址)
        AlipayClient client = new DefaultAlipayClient(AlipayConfig.URL, AlipayConfig.APPID,
                AlipayConfig.RSA_PRIVATE_KEY, AlipayConfig.FORMAT, AlipayConfig.CHARSET,
                AlipayConfig.ALIPAY_PUBLIC_KEY,AlipayConfig.SIGNTYPE);
        //创建请求对象： 携带请求参数
        AlipayTradeWapPayRequest alipay_request=new AlipayTradeWapPayRequest();

        // 封装请求支付信息
        AlipayTradeWapPayModel model=new AlipayTradeWapPayModel();
        model.setOutTradeNo(out_trade_no);
        model.setSubject(subject);
        model.setTotalAmount(total_amount);
        model.setBody(null);
        model.setProductCode(product_code);
        alipay_request.setBizModel(model);
        // 设置异步通知地址: 支付宝将用户支付结果通知给我们时 我们接受通知的接口
        alipay_request.setNotifyUrl(AlipayConfig.notify_url);
        // 设置同步地址: 用户在支付宝支付页支付成功后 点击完成跳转回我们的项目的地址
        alipay_request.setReturnUrl(AlipayConfig.return_url);
        try {
            //保存支付交易日志
            PaymentInfo paymetInfo = new PaymentInfo();
            paymetInfo.setUserId(orderInfo.getUserId());
            paymetInfo.setOrderNo(orderNo.toString());
            paymetInfo.setAmount(orderInfo.getTotalAmount());
            paymetInfo.setPayType(2);
            //支付宝处理支付时生成的 唯一编号
//            paymetInfo.setOutOrderNo();
            paymetInfo.setContent(subject);
            paymetInfo.setPaymentStatus("0");//0表示未支付  其他表示支付业务已经处理
            //异步保存交易日志
            paymentInfoService.saveAsync(paymetInfo);
            // form自动提交表单生成
            // 调用SDK生成表单
            return client.pageExecute(alipay_request).getBody();
        } catch (AlipayApiException e) {
            // TODO Auto-generated catch block
//            e.printStackTrace();
            throw new SpzxException(ResultCodeEnum.ALIPAY_PAGE_ERROR,e);
        }
    }
    //支付后回调业务
    @Override
    public String alipayCallback(Map<String, String> params) {
        try {
            //使用回调的 订单编号查询交易日志
            String tradeNo = params.get("out_trade_no");
            PaymentInfo paymentInfo = paymentInfoService.getOne(Wrappers.lambdaQuery(PaymentInfo.class)
                    .eq(PaymentInfo::getOrderNo, tradeNo));
            //1、验签：
            boolean verify_result = AlipaySignature
                    .rsaCheckV1(params, AlipayConfig.ALIPAY_PUBLIC_KEY, AlipayConfig.CHARSET,
                            AlipayConfig.SIGNTYPE);
            if(!verify_result){
                //更新日志
                if(paymentInfo!=null){
                    paymentInfo.setCallbackTime(new Date());
                    paymentInfo.setCallbackContent(JSON.toJSONString(params));
                    paymentInfo.setPaymentStatus("-2");//支付失败： -2 表示签名验证失败
                    paymentInfo.setOutTradeNo(params.get("trade_no"));//获取支付宝的交易流水号
                    paymentInfoService.updateById(paymentInfo);
                }
                throw new SpzxException(ResultCodeEnum.FAIL,null);
            }
            String tradeStatus = params.get("trade_status");
            //2、支付宝处理支付的状态校验
            if (StringUtils.isEmpty(tradeStatus) || !tradeStatus.equals("TRADE_SUCCESS")){
                //不是交易成功的状态：
                //可以考虑将 交易日志的状态改为失败......
                //更新日志
                if(paymentInfo!=null){
                    paymentInfo.setCallbackTime(new Date());
                    paymentInfo.setCallbackContent(JSON.toJSONString(params));
                    paymentInfo.setPaymentStatus("-1");//支付失败： -1 交易失败 可能时超时关闭
                    paymentInfo.setOutTradeNo(params.get("trade_no"));//获取支付宝的交易流水号
                    paymentInfoService.updateById(paymentInfo);
                }
                return "success";
            }
            //3、判断该笔订单是否在商户网站中已经做过处理
            if(paymentInfo==null){
                //非法请求：回调携带的订单号不是我们的
                throw new SpzxException(ResultCodeEnum.FAIL,null);
            }
            //2、幂等性
            if(!paymentInfo.getPaymentStatus().equals("0")){
                //订单的回调业务已经处理过了
                return "success";
            }
            //3、支付金额校验
            BigDecimal buyerPayAmount = new BigDecimal(params.get("buyer_pay_amount"));
            if(paymentInfo.getAmount().doubleValue() != buyerPayAmount.doubleValue() ){
                //支付金额不一致
                //更新日志
                if(paymentInfo!=null){
                    paymentInfo.setCallbackTime(new Date());
                    paymentInfo.setCallbackContent(JSON.toJSONString(params));
                    paymentInfo.setPaymentStatus("-3");//支付失败： -3 交易失败 支付金额错误
                    paymentInfo.setOutTradeNo(params.get("trade_no"));//获取支付宝的交易流水号
                    paymentInfoService.updateById(paymentInfo);
                }
                throw new SpzxException(ResultCodeEnum.FAIL,null);
            }
            //4、支付成功业务：
            // 分布式场景中的 事务控制：
            //  订单支付状态
            //  订单对应的订单项销量库存更新
            orderClient.updateOrderInfo(paymentInfo.getOrderNo());
            //  支付日志的更新
            paymentInfo.setCallbackTime(new Date());
            paymentInfo.setCallbackContent(JSON.toJSONString(params));
            paymentInfo.setPaymentStatus("1");//支付成功
            paymentInfo.setOutTradeNo(params.get("trade_no"));//获取支付宝的交易流水号
            paymentInfoService.updateById(paymentInfo);
            return "success";
        } catch (Exception e) {
            e.printStackTrace();//打印支付失败的异常的堆栈日志
            //出现异常 返回回调失败
            return "fail";
        }
    }
}
